# -*- coding: utf-8 -*-
# @Time    : 2024/5/14 16:38
# @Author  : Kyln.Wu
# @Email   : kylnwu@qq.com
# @File    : to_weixin_draft.py
# @Software: PyCharm
import json
import os
import time
from io import BytesIO
import requests
import schedule
import urllib3
from PIL import Image
from loguru import logger

from examples.config import APPID, APPSECRET

urllib3.disable_warnings()


def create_post_content():
    """
    定义微信公众号图文消息模板
    """
    centent_part = f"""\
这里是正文部分，支持html标签，这里根据自己的业务来定义。
正文部分。
正文部分。
"""
    return centent_part


# ======================================
# 微信公众号发布消息代码开始
# ======================================
class ToWeixinDraft:
    def __init__(self):
        self.app_id = APPID
        self.app_secret = APPSECRET
        self.wx_access_token = self.get_access_token()

    def get_access_token(self):
        """
        获取公众号权限
        """
        access_token_resp = requests.get(
            f'https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&app_id={self.app_id}&secret={self.app_secret}')
        json_obj = json.loads(access_token_resp.text)
        access_token = json_obj.get('access_token')
        logger.info(f"access_token: {access_token}")

        return access_token

    # 获取公众号文章必须的title, digest, content, img_url，构造并返回多图文消息articles的结构
    def pack_articles(self):
        # 1 获取本次发布的所有文章的title, img_url, content, tags, intro, digest
        wx_title = f"你的文章标题"
        intro = f"你的文章正文内容"  # create_post_content()
        # 摘要，取前100个字符
        digest = intro[:100]
        img_url = f"网络上的图片链接地址"
        # 获取推送电影海报
        base_path = f"图片保存的绝对路径，如：/www/wwwroot/to_weixin_draft"
        img_file_name = f'正文加载的图片文件名，如xxxx.jpg'
        save_path = os.path.join(base_path, img_file_name)

        # 2 上传封面获取封面id
        wx_fm_img_id = self.upd_fm_pic(save_path, img_file_name, img_url)

        # 3 上传正文图片到微信公众号,并获取返回的url地址
        wx_all_imgs_url = self.upd_imgs(save_path, img_file_name)

        # 4 用微信公众号返回的图片地址替换content里面的图片地址，获取最后要发布的正文内容
        wx_content_header = f"""\
        <p style="text-align: center;">
          <a href="{wx_all_imgs_url}" class="pirobox_gall" title="{wx_title}">\
            <img src="{wx_all_imgs_url}" alt="{wx_title}" width="500" height="700">\
          </a>
        </p>
        <p style="text-align: center;">
          {intro}
        </p>
        """
        # 构造多图文消息articles结构
        wx_content = wx_content_header
        articles_dict = self.create_post_dict(wx_title, digest, wx_content, wx_fm_img_id)
        # logger.info(articles_lst)
        return articles_dict

    # 2 上传封面图片到微信公众号，并返回封面图片id
    def upd_fm_pic(self, save_path, img_file_name, img_url):
        headers = {
            'user-agent': 'Mozilla/5.0 (Windows NT 10.0; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/80.0.3987.87 Safari/537.36 SE 2.X MetaSr 1.0'
        }
        # 假设从网络上获取图片，如果是本地图片，省略以下requests代码
        resp = requests.get(img_url, headers=headers, verify=False)
        if resp.status_code == 200:
            # 使用BytesIO处理二进制数据
            image_data = BytesIO(resp.content)

            # 打开WebP图像文件
            image = Image.open(image_data)

            # 转换图像为JPG
            image_jpg = image.convert('RGB')

            # 保存转换后的图片到本地
            image_jpg.save(save_path, format='JPEG')

        url = f'https://api.weixin.qq.com/cgi-bin/material/add_material?access_token={self.wx_access_token}&type=image'
        request_file = {
            'media': (img_file_name, open(save_path, 'rb'), 'image/jpeg')}
        vx_res = requests.post(url=url, files=request_file)
        obj = json.loads(vx_res.content)
        logger.info(obj)
        return obj['media_id']

    # 3 上传正文图片到微信公众号，并返回正文图片网址
    def upd_imgs(self, save_path, img_file_name):
        vx_img_url = 'https://api.weixin.qq.com/cgi-bin/media/uploadimg'
        request_file = {
            'media': (img_file_name, open(save_path, 'rb'), 'image/jpeg')}
        data = {
            'access_token': self.wx_access_token
        }
        vx_res = requests.post(url=vx_img_url, files=request_file, data=data)
        obj = json.loads(vx_res.content)
        logger.info(obj)
        return obj['url']

    # 4 构造多图文消息体的articles部分
    def create_post_dict(self, wx_title, digest, wx_content, wx_fm_img_id):
        """
        接口请求说明
        http
        请求方式：POST（请使用https协议）https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN

        调用示例
        {
            "articles": [
                {
                    "title": TITLE,
                    "author": AUTHOR,
                    "digest": DIGEST,
                    "content": CONTENT,
                    "content_source_url": CONTENT_SOURCE_URL,
                    "thumb_media_id": THUMB_MEDIA_ID,
                    "show_cover_pic": 1,
                    "need_open_comment": 0,
                    "only_fans_can_comment": 0
                }
                // 若新增的是多图文素材，则此处应还有几段articles结构
        ]
        }
        """
        articles_dict = {
            "title": wx_title,
            "author": '',
            "digest": digest,
            "content": wx_content,
            "show_cover_pic": 1,
            "need_open_comment": 0,
            "only_fans_can_comment": 1,
            "thumb_media_id": wx_fm_img_id
        }
        return articles_dict

    # 4 构造多图文消息体的articles部分
    def create_post_dict(self):
        """
        接口请求说明
        http
        请求方式：POST（请使用https协议）https://api.weixin.qq.com/cgi-bin/draft/add?access_token=ACCESS_TOKEN

        调用示例
        {
            "articles": [
                {
                    "title": TITLE,
                    "author": AUTHOR,
                    "digest": DIGEST,
                    "content": CONTENT,
                    "content_source_url": CONTENT_SOURCE_URL,
                    "thumb_media_id": THUMB_MEDIA_ID,
                    "show_cover_pic": 1,
                    "need_open_comment": 0,
                    "only_fans_can_comment": 0
                }
                // 若新增的是多图文素材，则此处应还有几段articles结构
        ]
        }
        """

        articles_dict = {
            "title": "wx_title",
            "author": '',
            "digest": "digest",
            "content": "wx_content",
            "show_cover_pic": 1,
            "need_open_comment": 0,
            "only_fans_can_comment": 1,
            "thumb_media_id": "wx_fm_img_id"
        }
        return articles_dict

    # post到公众号草稿箱
    def upd_post2cgx(self, data):
        url = 'https://api.weixin.qq.com/cgi-bin/draft/add?access_token=' + self.wx_access_token
        vx_res = requests.post(url=url, data=json.dumps(data, ensure_ascii=False).encode("utf-8"))
        res_obj = json.loads(vx_res.content)
        logger.info(res_obj)
        if 'errmsg' in res_obj:
            logger.error("公众号上传失败。")
            return False
        else:
            logger.warning("公众号上传成功。")
            return True


# 运行主函数
def do_job():
    try:
        # 先实例化上传到微信公众号的类
        do_weixin_draft = ToWeixinDraft()
        # 组织文章内容
        data = do_weixin_draft.create_post_dict()
        # 上传到微信公众号草稿箱
        res_msg = do_weixin_draft.upd_post2cgx(data)
        n = 1
        # 如果上传失败，尝试3次，每次间隔159秒
        while not res_msg:
            res_msg = do_weixin_draft.upd_post2cgx(data)
            n += 1
            time.sleep(159)
            if n == 3:
                logger.error('公众号发布尝试3次失败，退出。')
                break
    except Exception as e:
        logger.error(e)


if __name__ == '__main__':
    # 部署情况
    # schedule.every(10).minutes.do(do_job)  # 部署每10分钟执行一次do_job()函数的任务
    # schedule.every().hour.do(do_job)  # 部署每×小时执行一次do_job()函数的任务
    # schedule.every().day.at("10:30").do(do_job)  # 部署在每天的10:30执行do_job()函数的任务
    # # schedule.every().monday.do(do_job)  # 部署每个星期一执行do_job()函数的任务
    # # schedule.every().wednesday.at("13:15").do(do_job)  # 部署每周三的13：15执行函数的任务
    #
    # while True:
    #     schedule.run_pending()
    #     time.sleep(1)
    do_job()
